package com.xyl;


import sun.misc.Unsafe;

import java.lang.reflect.Field;

/**
 * 使用堆外内存的原因
 * 对垃圾回收停顿的改善，从而在GC时减少回收停顿对于应用的影响。
 * 提升程序I/O操作的性能。
 * 通常在I/O通信过程中，会存在堆内内存到堆外内存的数据拷贝操作，
 * 对于需要频繁进行内存间数据拷贝且生命周期较短的暂存数据，都建议存储到堆外内存
 * <p>
 * <p>
 * Java中对堆外内存的操作依赖于Unsafe提供的操作堆外内存的native方法
 * Java中的魔法类-Unsafe位于sun.misc包
 * 主要提供一些用于执行低级别，不安全操作的方法
 * 如直接访问系统内存资源、自主管理内存资源等，
 * 这些方法在提升Java运行效率、增强Java语言底层资源操作能力方面起到了很大的作用。
 * <p>
 * 作者不希望我们使用它，虽然获取到对底层的控制权，但是也增大了风险。
 * 该类默认被BootstrapClassLoader加载。
 * 我们在程序中去调用这个类的话类加载器肯定是AppClassLoader
 * 提供了一个静态方法去获取当前类实例。
 * 在getUnsafe()方法中首先判断当前类加载器是否为空，因为使用 BootstrapClassLoader 本身就是空，它是用c++实现的，这样就限制了我们在自己的代码中使用这个类。
 * <p>
 * 作者也算是给我们提供了一个后门，因为Java有反射机制。
 * 调用的思路就是将theUnsafe对象设置为可见。
 * <p>
 * 内存操作主要包含堆外内存的分配、拷贝、释放、给定地址值操作等方法。
 * //分配内存相当于C++的malloc函数
 * public native long allocateMemory(long bytes)
 * //扩充内存
 * public native long reallocateMemory(long address, long bytes);
 * //释放内存
 * public native void freeMemory(long address);
 * //在给定的内存块中设置值
 * public native void setMemory(Object o, long offset, long bytes, byte value);
 * //内存拷贝
 * public native void copyMemory(Object srcBase, long srcOffset, Object destBase, long destOffset, long bytes);
 * //获取给定地址值，忽略修饰限定符的访问限制。与此类似操作还有: getInt，getDouble，getLong，getChar等
 * public native Object getObject(Object o, long offset);
 * //为给定地址设置值，忽略修饰限定符的访问限制，与此类似操作还有: putInt,putDouble，putLong，putChar等
 * public native void putObject(Object o, long offset, Object x);
 * //获取给定地址的byte类型的值（当且仅当该内存地址为allocateMemory分配时，此方法结果为确定的）
 * public native byte getByte(long address);
 * //为给定地址设置byte类型的值（当且仅当该内存地址为allocateMemory分配时，此方法结果才是确定的）
 * public native void putByte(long address, byte x);
 * <p>
 * Unsafe中提供了三个方法来操作内存屏障：
 * <p>
 * //读屏障，禁止load操作重排序。屏障前的load操作不能被重排序到屏障后，屏障后的load操作不能被重排序到屏障前
 * //实现了LoadLoad禁止了指令的重排序
 * public native void loadFence();
 * //写屏障，禁止store操作重排序。屏障前的store操作不能被重排序到屏障后，屏障后的store操作不能被重排序到屏障前
 * //实现了StoreStore
 * public native void storeFence();
 * //全能屏障，禁止load、store操作重排序
 * //实现了StoreLoad
 * public native void fullFence();
 * <p>
 * 系统相关
 * <p>
 * //返回系统指针的大小。返回值为4（32位系统）或 8（64位系统）。
 * public native int addressSize();
 * //内存页的大小，此值为2的幂次方。
 * public native int pageSize();
 * <p>
 * 线程调度
 * <p>
 * 线程调度中提供的方法包括：线程的挂起，恢复和对象锁机制等，其中获取对象的监视器锁方法已经被标记为弃用。
 * <p>
 * // 终止挂起的线程，恢复正常.java.util.concurrent包中挂起操作都是在LockSupport类实现的，其底层正是使用这两个方法
 * public native void unpark(Object thread);
 * // 线程调用该方法，线程将一直阻塞直到超时，或者是中断条件出现。
 * public native void park(boolean isAbsolute, long time);
 * //获得对象锁（可重入锁）
 *
 * @Deprecated public native void monitorEnter(Object o);
 * //释放对象锁
 * @Deprecated public native void monitorExit(Object o);
 * //尝试获取对象锁
 * @Deprecated public native boolean tryMonitorEnter(Object o);
 * <p>
 * 对象操作
 * 提供了多个方法来进行对象实例化和获取对象的偏移地址的操作：
 * <p>
 * // 传入一个Class对象并创建该实例对象，但不会调用构造方法
 * public native Object allocateInstance(Class<?> cls) throws InstantiationException;
 * <p>
 * // 获取字段f在实例对象中的偏移量
 * public native long objectFieldOffset(Field f);
 * <p>
 * // 返回值就是f.getDeclaringClass()
 * public native Object staticFieldBase(Field f);
 * // 静态属性的偏移量，用于在对应的Class对象中读写静态属性
 * public native long staticFieldOffset(Field f);
 * <p>
 * // 获得给定对象偏移量上的int值，所谓的偏移量可以简单理解为指针指向该变量；的内存地址，
 * // 通过偏移量便可得到该对象的变量，进行各种操作
 * public native int getInt(Object o, long offset);
 * // 设置给定对象上偏移量的int值
 * public native void putInt(Object o, long offset, int x);
 * <p>
 * // 获得给定对象偏移量上的引用类型的值
 * public native Object getObject(Object o, long offset);
 * // 设置给定对象偏移量上的引用类型的值
 * public native void putObject(Object o, long offset, Object x););
 * <p>
 * // 设置给定对象的int值，使用volatile语义，即设置后立马更新到内存对其他线程可见
 * public native void putIntVolatile(Object o, long offset, int x);
 * // 获得给定对象的指定偏移量offset的int值，使用volatile语义，总能获取到最新的int值。
 * public native int getIntVolatile(Object o, long offset);
 * <p>
 * // 与putIntVolatile一样，但要求被操作字段必须有volatile修饰
 * public native void putOrderedInt(Object o, long offset, int x);
 * allocateInstance方法在这几个场景下很有用：跳过对象的实例化阶段（通过构造函数）、忽略构造函数的安全检查（反射newInstance()时）、你需要某类的实例但该类没有public的构造函数。
 * <p>
 * <p>
 * class相关操作
 * //静态属性的偏移量，用于在对应的Class对象中读写静态属性
 * public native long staticFieldOffset(Field f);
 * //获取一个静态字段的对象指针
 * public native Object staticFieldBase(Field f);
 * //判断是否需要初始化一个类，通常在获取一个类的静态属性的时候（因为一个类如果没初始化，它的静态属性也不会初始化）使用。 当且仅当ensureClassInitialized方法不生效时返回false
 * public native boolean shouldBeInitialized(Class<?> c);
 * //确保类被初始化
 * public native void ensureClassInitialized(Class<?> c);
 * //定义一个类，可用于动态创建类，此方法会跳过JVM的所有安全检查，默认情况下，ClassLoader（类加载器）和ProtectionDomain（保护域）实例来源于调用者
 * public native Class<?> defineClass(String name, byte[] b, int off, int len,
 * ClassLoader loader,
 * ProtectionDomain protectionDomain);
 * //定义一个匿名类，可用于动态创建类
 * public native Class<?> defineAnonymousClass(Class<?> hostClass, byte[] data, Object[] cpPatches);
 * 数组 操作
 * 数组操作主要有两个方法：
 * <p>
 * //返回数组中第一个元素的偏移地址
 * public native int arrayBaseOffset(Class<?> arrayClass);
 * //返回数组中一个元素占用的大小
 * public native int arrayIndexScale(Class<?> arrayClass);
 * <p>
 * Unsafe类中提供了三个方法来进行CAS操作：
 * <p>
 * public final native boolean compareAndSwapObject(Object o, long offset,  Object expected, Object update);
 * <p>
 * public final native boolean compareAndSwapInt(Object o, long offset, int expected,int update);
 * <p>
 * public final native boolean compareAndSwapLong(Object o, long offset, long expected, long update);
 * 另外，在 JDK1.8中新增了几个 CAS 的方法，他们的实现是基于上面三个方法做的一层封装：
 */
public class UnsafeTest {

    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, InterruptedException {
        Field theUnsafeField = Unsafe.class.getDeclaredField("theUnsafe");
        theUnsafeField.setAccessible(true);
        Unsafe unsafe = (Unsafe) theUnsafeField.get(null);
        System.out.println(unsafe);

    }
}



